import { Command } from 'commander';
import inquirer from 'inquirer';
import { api } from '../services/api';
import { config } from '../services/config';
import { logger } from '../utils/logger';
import { createTable } from '../utils/table';
import { requireAuth, requireProject, validateEnvironmentName } from '../utils/validation';
import { CLIError, Environment } from '../types';

export function envCommands(program: Command): void {
  const envCmd = program
    .command('env')
    .description('Environment management commands');

  envCmd
    .command('list')
    .description('List all environments')
    .action(async () => {
      try {
        requireAuth();
        const projectId = requireProject();

        const spinner = logger.spinner('Fetching environments...');
        try {
          const environments = await api.getEnvironments(projectId);
          spinner.succeed();

          if (environments.length === 0) {
            logger.info('No environments found. Create one with "cm env create <name>"');
            return;
          }

          const currentEnv = config.getCurrentEnvironment();
          const headers = ['', 'Name', 'Type', 'Modules', 'Secrets'];
          const rows = environments.map(env => [
            env.name === currentEnv ? '*' : ' ',
            env.name,
            env.type,
            env.modules?.length.toString() || '0',
            Object.keys(env.secrets || {}).length.toString()
          ]);

          logger.log('\n' + createTable(headers, rows));
          logger.info('\n* = current environment');
        } catch (error) {
          spinner.fail();
          throw error;
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to list environments');
      }
    });

  envCmd
    .command('create <name>')
    .description('Create a new environment')
    .option('-t, --type <type>', 'Environment type (dev, staging, prod)', 'dev')
    .action(async (name: string, options) => {
      try {
        requireAuth();
        const projectId = requireProject();

        if (!validateEnvironmentName(name)) {
          throw new CLIError('Invalid environment name. Use only letters, numbers, hyphens, and underscores.');
        }

        let { type } = options;
        
        if (!['dev', 'staging', 'prod'].includes(type)) {
          const answers = await inquirer.prompt([
            {
              type: 'list',
              name: 'type',
              message: 'Environment type:',
              choices: [
                { name: 'Development', value: 'dev' },
                { name: 'Staging', value: 'staging' },
                { name: 'Production', value: 'prod' }
              ],
              default: 'dev'
            }
          ]);
          type = answers.type;
        }

        const spinner = logger.spinner('Creating environment...');
        try {
          const environment = await api.createEnvironment(projectId, name, type);
          spinner.succeed();
          
          logger.success(`Environment "${environment.name}" created successfully`);
          logger.info(`Type: ${environment.type}`);
          
          if (name === 'dev' || config.getCurrentEnvironment() === 'dev') {
            const useEnv = await inquirer.prompt([
              {
                type: 'confirm',
                name: 'use',
                message: 'Set as current environment?',
                default: true
              }
            ]);

            if (useEnv.use) {
              config.setCurrentEnvironment(environment.name);
              logger.success(`Switched to environment "${environment.name}"`);
            }
          }
        } catch (error) {
          spinner.fail();
          throw error;
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to create environment');
      }
    });

  envCmd
    .command('use <name>')
    .description('Switch to an environment')
    .action(async (name: string) => {
      try {
        requireAuth();
        const projectId = requireProject();

        const spinner = logger.spinner('Fetching environments...');
        try {
          const environments = await api.getEnvironments(projectId);
          spinner.succeed();

          const environment = environments.find(e => e.name === name || e.id === name);
          if (!environment) {
            throw new CLIError(`Environment "${name}" not found`);
          }

          config.setCurrentEnvironment(environment.name);
          logger.success(`Switched to environment "${environment.name}" (${environment.type})`);
        } catch (error) {
          if (error instanceof CLIError) {
            throw error;
          }
          spinner.fail();
          throw new CLIError('Failed to switch environment');
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to switch environment');
      }
    });

  envCmd
    .command('info')
    .description('Show current environment information')
    .action(async () => {
      try {
        requireAuth();
        const projectId = requireProject();
        const currentEnvName = config.getCurrentEnvironment();

        const spinner = logger.spinner('Fetching environment information...');
        try {
          const environments = await api.getEnvironments(projectId);
          const environment = environments.find(e => e.name === currentEnvName);
          
          if (!environment) {
            throw new CLIError(`Environment "${currentEnvName}" not found`);
          }
          
          spinner.succeed();

          logger.log(`\nEnvironment Information:`);
          logger.log(`Name: ${environment.name}`);
          logger.log(`Type: ${environment.type}`);
          logger.log(`ID: ${environment.id}`);
          
          if (environment.modules && environment.modules.length > 0) {
            logger.log(`\nInstalled Modules: ${environment.modules.length}`);
            environment.modules.forEach(mod => {
              logger.log(`  • ${mod.moduleId}@${mod.version}`);
            });
          } else {
            logger.log(`\nNo modules installed`);
          }

          const secretCount = Object.keys(environment.secrets || {}).length;
          logger.log(`\nSecrets: ${secretCount} configured`);
          
          if (secretCount > 0) {
            logger.log(`Secret keys:`);
            Object.keys(environment.secrets).forEach(key => {
              logger.log(`  • ${key}`);
            });
          }
        } catch (error) {
          spinner.fail();
          throw error;
        }
      } catch (error) {
        if (error instanceof CLIError) {
          throw error;
        }
        throw new CLIError('Failed to get environment information');
      }
    });
}